package com.deepocean.service.impl;

import com.deepocean.common.entity.ResultEntity;
import com.deepocean.dao.*;
import com.deepocean.entity.process.*;
import com.deepocean.service.IProcessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Service("ProcessServiceImpl")
public class ProcessServiceImpl implements IProcessService {
    @Autowired
    GradingScreenDao gradingScreenDao;
    @Autowired
    JigDao jigDao;
    @Autowired
    CentrifugeDao centrifugeDao;
    @Autowired
    DeslimingScreenDao deslimingScreenDao;
    @Autowired
    HierarchicalCycloneDao hierarchicalCycloneDao;
    @Autowired
    FloatationDao floatationDao;
    @Autowired
    TBSDao tbsDao;
    @Autowired
    LinearScreenDao linearScreenDao;
    @Autowired
    CurvedScreenDao curvedScreenDao;
    @Autowired
    DenseMediumCycloneDao denseMediumCycloneDao;
    @Autowired
    DetachmentScreenDao detachmentScreenDao;
    @Autowired
    CycloneProcessDao cycloneProcessDao;
    @Autowired
    ProcessEngineDao processEngineDao;
    @Autowired
    ProcessRelationDao processRelationDao;

    private static final Double WATER_INPUT_ONE_TON = 5.83;

    @Override
    public ResultEntity processStart(Double rawCoal) {
        String id = getRandomId();
        // 分级筛
        // 矸石产出
        GradingScreenProcessEntity gradingScreenProcess = gradingScreenProcess(rawCoal, id);
        // 跳汰机
        // 矸石产出
        JigProcessEntity jigProcess = jigProcess(gradingScreenProcess.getMineralOutput(), id);
        // 离心机
        // 中煤仓产品
        CentrifugeProcessEntity centrifugeProcess = centrifugeProcess(jigProcess.getMineralOutput(), id);



        // 主洗车间
        // 脱泥筛
        DeslimingScreenProcessEntity deslimingScreenProcessEntity = deslimingScreenProcess(gradingScreenProcess.getLt50mmMineral(), id);
        // 分级旋流器
        HierarchicalCycloneProcessEntity hierarchicalCycloneProcessEntity = hierarchicalCycloneProcess(deslimingScreenProcessEntity.getLt1mmCoal(), id);
        // 浮选机
        // 精煤产品
        FloatationMachineProcessEntity floatationMachineProcessEntity = floatationMachineProcess(hierarchicalCycloneProcessEntity.getLt025Coal(), id);
        // TBS干扰床分选机
        TBSProcessEntity tbsProcessEntity = tbsProcess(hierarchicalCycloneProcessEntity.getGt025Coal(), id);
        // 直线筛
        LinearScreenProcessEntity linearScreenProcessEntity = linearScreenProcess(tbsProcessEntity.getCleanCoalOutput(), id);
        // 弧形筛
        CurvedScreenProcessEntity curvedScreenProcessEntity = curvedScreenProcess(linearScreenProcessEntity.getCleanCoalOutput(), id);
        // 离心机
        // 精煤产品
        CentrifugeProcessEntity centrifugeProcessEntity = centrifugeProcess(curvedScreenProcessEntity.getCleanCoalOutput(), id);
        // 重介旋流器
        DenseMediumCycloneProcessEntity denseMediumCycloneProcessEntity = denseMediumCycloneProcess(deslimingScreenProcessEntity.getGt1mmCoal(), id);
        // 脱介筛
        DetachmentScreenProcessEntity detachmentScreenProcessEntity = detachmentScreenProcess(denseMediumCycloneProcessEntity.getCleanCoal(), id);
        // 离心机
        // 精煤产出
        CentrifugeProcessEntity centrifuge = centrifugeProcess(detachmentScreenProcessEntity.getCleanCoalOutput(), id);

        // 脱介筛
        DetachmentScreenProcessEntity detachmentScreen = detachmentScreenProcess(denseMediumCycloneProcessEntity.getCoalGangueMixture(), id);
        // 旋流器
        CycloneProcessEntity cycloneProcessEntity = cycloneProcess(detachmentScreen.getCleanCoalOutput(), id);
        // 脱介筛
        // 矸石产出
        DetachmentScreenProcessEntity detachmentScreenProcess = detachmentScreenProcess(cycloneProcessEntity.getMediumCoal(), id);

        // 离心机
        // 中煤产出
        CentrifugeProcessEntity centrifuge2 = centrifugeProcess(detachmentScreenProcess.getCleanCoalOutput(), id);

        // 中煤
        Double coalOutput = centrifugeProcess.getCoalOutput();
        Double coalOutput2 = centrifuge2.getCoalOutput();
        double totalMediaCoal = BigDecimal.valueOf(coalOutput).add(BigDecimal.valueOf(coalOutput2)).doubleValue();


        // 精煤
        Double cleanCoal = floatationMachineProcessEntity.getCleanCoalOutput();
        Double cleanCoal2 = centrifugeProcessEntity.getCoalOutput();
        Double cleanCoal3 = centrifuge.getCoalOutput();
        double totalCleanCoal = BigDecimal.valueOf(cleanCoal).add(BigDecimal.valueOf(cleanCoal2)).add(BigDecimal.valueOf(cleanCoal3)).doubleValue();

        // 矸石
        Double gangue = gradingScreenProcess.getGangueOutput();
        Double gangue2 = jigProcess.getGangueOutput();
        Double gangue3 = detachmentScreenProcess.getMediaOutput();
        double totalGangue = BigDecimal.valueOf(gangue).add(BigDecimal.valueOf(gangue2)).add(BigDecimal.valueOf(gangue3)).doubleValue();

        // 返回实体
        ProcessEntity processEntity = new ProcessEntity();
        processEntity.setId(id);
        processEntity.setCleanCoal(totalCleanCoal);
        processEntity.setGangue(totalGangue);
        processEntity.setRawCoal(rawCoal);
        processEntity.setMediaCoal(totalMediaCoal);

        processEngineDao.addProcess(processEntity);
        return ResultEntity.success(processEntity);
    }

    @Override
    public ResultEntity processRelation(Double rawCoal, Integer craftType) {
        List<ProcessRelationEntity> processEntityList = processRelationDao.selectByCraftType(craftType);

        ProcessRelationEntity processRelationEntity = processEntityList.stream()
                .filter(entity -> entity.getParentDeviceId().equals("0"))
                .findFirst()
                .orElse(null);

        // 层级结构
        ProcessRelationEntity hierarchy = getHierarchy(processRelationEntity, processEntityList);

        doProcess(hierarchy, rawCoal, null);
        System.out.println(hierarchy);
        return null;
    }

    @Override
    public boolean updateRelation(List<ProcessRelationEntity> list) {
        return false;
    }

    @Override
    public boolean addRelation(List<ProcessRelationEntity> list) {
        return false;
    }

    private void doProcess(ProcessRelationEntity processRelationEntity, Double input, ProcessRelationEntity parentEntity) {
        String id = getRandomId();

        String className = processRelationEntity.getClassName();
        String inputName = processRelationEntity.getInputName();
        String daoName = processRelationEntity.getDaoName();
        String methodName = processRelationEntity.getMethodName();
        String outputName = processRelationEntity.getOutputName();
        String parentDeviceId = processRelationEntity.getParentDeviceId();

        if (parentDeviceId.equals("0")) {
            // 顶级父类
            try {
                Method method = this.getClass().getDeclaredMethod(methodName);
                // 调用执行算法
                method.invoke(this, input, id);

            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

    }

    private void invokeAlgorithm(Type type, Object obj) {
        if (type instanceof GradingScreenProcessEntity) {
            GradingScreenProcessEntity entity =  (GradingScreenProcessEntity) obj;

        }
    }

    /**
     * 获取层级结构
     * @param parent
     * @param allList
     * @return
     */
    private ProcessRelationEntity getHierarchy(ProcessRelationEntity parent, List<ProcessRelationEntity> allList) {
        List<ProcessRelationEntity> children = new ArrayList<>();

        allList.forEach(entity -> {
            if (entity.getParentDeviceId().equals(parent.getDeviceId())) {
                children.add(entity);
                getHierarchy(entity, allList);
            }
        });
        parent.setChildren(children);
        return parent;
    }

    /**
     * 分级筛流程
     * @param rawCoal
     * @param processId
     * @return
     */
    private GradingScreenProcessEntity gradingScreenProcess(Double rawCoal, String processId) {
        GradingScreenProcessEntity gradingScreen = new GradingScreenProcessEntity();
        gradingScreen.setMaterialInput(rawCoal);
        // 理论矸石输出算法
        BigDecimal rowCoalNum = BigDecimal.valueOf(rawCoal);
        BigDecimal bigDecimalGangueOutput = rowCoalNum.multiply(BigDecimal.valueOf(0.1));
        double gangueOutput = bigDecimalGangueOutput.doubleValue();
        // 理论矿产lt50mm算法
        BigDecimal bigDecimalLt50mm = rowCoalNum.subtract(bigDecimalGangueOutput).multiply(BigDecimal.valueOf(0.4));
        double lt50mm = bigDecimalLt50mm.doubleValue();
        // 理论矿产gt50,lt200算法
        double mineralOutput = rowCoalNum.subtract(bigDecimalGangueOutput).subtract(bigDecimalLt50mm).doubleValue();

        gradingScreen.setGangueOutput(gangueOutput);
        gradingScreen.setLt50mmMineral(lt50mm);
        gradingScreen.setMineralOutput(mineralOutput);
        gradingScreen.setId(getRandomId());
        gradingScreen.setProcessId(processId);

        // 分级筛理论流程数据入库
        gradingScreenDao.addProcess(gradingScreen);
        return gradingScreen;
    }

    /**
     * 跳汰机
     * @param materialInput
     * @param processId
     * @return
     */
    private JigProcessEntity jigProcess(Double materialInput, String processId) {
        JigProcessEntity jigProcess = new JigProcessEntity();
        // 矸石输出理论算法
        BigDecimal bgMaterialInput = BigDecimal.valueOf(materialInput);
        BigDecimal bgGangue = bgMaterialInput.multiply(BigDecimal.valueOf(0.1));
        double gangue = bgGangue.doubleValue();
        // 矿物输出算法
        double mineralOutput = bgMaterialInput.subtract(bgGangue).doubleValue();

        jigProcess.setMaterialInput(materialInput);
        jigProcess.setProcessId(processId);
        jigProcess.setId(getRandomId());
        jigProcess.setGangueOutput(gangue);
        jigProcess.setMineralOutput(mineralOutput);
        jigDao.addProcess(jigProcess);
        return jigProcess;
    }

    /**
     * 离心机
     * @param materialInput
     * @param processId
     * @return
     */
    private CentrifugeProcessEntity centrifugeProcess(Double materialInput, String processId) {
        CentrifugeProcessEntity centrifugeProcess = new CentrifugeProcessEntity();
        // 理论水输出
        BigDecimal bdMaterialInput = BigDecimal.valueOf(materialInput);
        BigDecimal bdWater = bdMaterialInput.multiply(BigDecimal.valueOf(0.1)).add(BigDecimal.valueOf(WATER_INPUT_ONE_TON));
        double water = bdWater.doubleValue();

        double coal = bdMaterialInput.subtract(bdMaterialInput.multiply(BigDecimal.valueOf(0.1))).doubleValue();

        centrifugeProcess.setProcessId(processId);
        centrifugeProcess.setId(getRandomId());
        centrifugeProcess.setMaterialInput(materialInput);
        centrifugeProcess.setWaterOutput(water);
        centrifugeProcess.setCoalOutput(coal);
        centrifugeDao.addProcess(centrifugeProcess);

        return centrifugeProcess;
    }

    /**
     * 脱泥筛
     * @param materialInput
     * @param processId
     * @return
     */
    private DeslimingScreenProcessEntity deslimingScreenProcess(Double materialInput, String processId) {
        DeslimingScreenProcessEntity deslimingScreenProcessEntity = new DeslimingScreenProcessEntity();
        deslimingScreenProcessEntity.setProcessId(processId);
        deslimingScreenProcessEntity.setId(getRandomId());
        deslimingScreenProcessEntity.setMaterialInput(materialInput);
        // 计算小于1mm矿物理论值
        BigDecimal bdMaterialInput = BigDecimal.valueOf(materialInput);
        BigDecimal bdLt1mm = bdMaterialInput.multiply(BigDecimal.valueOf(0.4));
        double lt1mm = bdLt1mm.doubleValue();
        // 计算大于1mm矿物理论值
        double gt1mm = bdMaterialInput.subtract(bdLt1mm).doubleValue();
        deslimingScreenProcessEntity.setLt1mmCoal(lt1mm);
        deslimingScreenProcessEntity.setGt1mmCoal(gt1mm);

        deslimingScreenDao.addProcess(deslimingScreenProcessEntity);

        return deslimingScreenProcessEntity;
    }

    /**
     * 分级旋流器
     * @param input
     * @param processId
     * @return
     */
    private HierarchicalCycloneProcessEntity hierarchicalCycloneProcess(Double input, String processId) {
        HierarchicalCycloneProcessEntity hierarchicalCycloneProcessEntity = new HierarchicalCycloneProcessEntity();
        hierarchicalCycloneProcessEntity.setProcessId(processId);
        hierarchicalCycloneProcessEntity.setId(getRandomId());
        hierarchicalCycloneProcessEntity.setMaterialInput(input);

        // 计算小于0.25mm物理理论值
        BigDecimal bdInput = BigDecimal.valueOf(input);
        BigDecimal bdLt025 = bdInput.multiply(BigDecimal.valueOf(0.3));
        double lt025 = bdLt025.doubleValue();

        // 计算大于0.25mm物理理论值
        double gt025 = bdInput.subtract(bdLt025).doubleValue();
        hierarchicalCycloneProcessEntity.setLt025Coal(lt025);
        hierarchicalCycloneProcessEntity.setGt025Coal(gt025);

        hierarchicalCycloneDao.addProcess(hierarchicalCycloneProcessEntity);

        return hierarchicalCycloneProcessEntity;
    }

    /**
     * 浮选机
     * @param input
     * @param processId
     * @return
     */
    private FloatationMachineProcessEntity floatationMachineProcess(Double input, String processId) {
        FloatationMachineProcessEntity floatationMachineProcessEntity = new FloatationMachineProcessEntity();
        floatationMachineProcessEntity.setProcessId(processId);
        floatationMachineProcessEntity.setId(getRandomId());
        floatationMachineProcessEntity.setMaterialInput(input);

        // 精煤理论算法
        BigDecimal bdInput = BigDecimal.valueOf(input);
        BigDecimal bdCleanCoal = bdInput.multiply(BigDecimal.valueOf(0.92));
        double cleanCoal = bdCleanCoal.doubleValue();

        // 杂质理论算法
        double impurityOutput = bdInput.subtract(bdCleanCoal).doubleValue();

        floatationMachineProcessEntity.setCleanCoalOutput(cleanCoal);
        floatationMachineProcessEntity.setImpurityOutput(impurityOutput);

        floatationDao.addProcess(floatationMachineProcessEntity);

        return floatationMachineProcessEntity;
    }

    /**
     * TBS
     * @param input
     * @param processId
     * @return
     */
    private TBSProcessEntity tbsProcess(Double input, String processId) {
        TBSProcessEntity tbsProcessEntity = new TBSProcessEntity();
        tbsProcessEntity.setProcessId(processId);
        tbsProcessEntity.setId(getRandomId());
        tbsProcessEntity.setMaterialInput(input);
        // 精矿获得算法
        BigDecimal bdInput = BigDecimal.valueOf(input);
        BigDecimal bdCleanCoal = bdInput.multiply(BigDecimal.valueOf(0.88));
        double cleanCoal = bdCleanCoal.doubleValue();

        // 粗矿获得算法
        double coarseOre = bdInput.subtract(bdCleanCoal).doubleValue();

        tbsProcessEntity.setCleanCoalOutput(cleanCoal);
        tbsProcessEntity.setCoarseOreOutput(coarseOre);

        tbsDao.addProcess(tbsProcessEntity);

        return tbsProcessEntity;
    }

    /**
     * 直线筛
     * @param input
     * @param processId
     * @return
     */
    private LinearScreenProcessEntity linearScreenProcess(Double input, String processId) {
        LinearScreenProcessEntity linearScreenProcessEntity = new LinearScreenProcessEntity();
        linearScreenProcessEntity.setProcessId(processId);
        linearScreenProcessEntity.setId(getRandomId());
        linearScreenProcessEntity.setMaterialInput(input);
        // 晒上精煤算法
        BigDecimal bdInput = BigDecimal.valueOf(input);
        BigDecimal bdCleanCoalOutput = bdInput.multiply(BigDecimal.valueOf(0.98));
        double cleanCoal = bdCleanCoalOutput.doubleValue();

        // 晒下粗矿算法
        double impurityOutput = bdInput.subtract(bdCleanCoalOutput).doubleValue();

        linearScreenProcessEntity.setCleanCoalOutput(cleanCoal);
        linearScreenProcessEntity.setImpurityOutput(impurityOutput);

        linearScreenDao.addProcess(linearScreenProcessEntity);

        return linearScreenProcessEntity;

    }

    /**
     * 弧形筛
     * @param input
     * @param processId
     * @return
     */
    private CurvedScreenProcessEntity curvedScreenProcess(Double input, String processId) {
        CurvedScreenProcessEntity curvedScreenProcessEntity = new CurvedScreenProcessEntity();
        curvedScreenProcessEntity.setProcessId(processId);
        curvedScreenProcessEntity.setId(getRandomId());
        curvedScreenProcessEntity.setMaterialInput(input);

        // 筛上精煤算法
        BigDecimal bdInput = BigDecimal.valueOf(input);
        BigDecimal bdCleanCoal = bdInput.multiply(BigDecimal.valueOf(0.95));
        double cleanCoal = bdCleanCoal.doubleValue();

        // 晒下杂质算法
        double impurityOutput = bdInput.subtract(bdCleanCoal).doubleValue();

        curvedScreenProcessEntity.setCleanCoalOutput(cleanCoal);
        curvedScreenProcessEntity.setImpurityOutput(impurityOutput);

        curvedScreenDao.addProcess(curvedScreenProcessEntity);

        return curvedScreenProcessEntity;
    }

    /**
     * 重介旋流器
     * @param input
     * @param processId
     * @return
     */
    private DenseMediumCycloneProcessEntity denseMediumCycloneProcess(Double input, String processId) {
        DenseMediumCycloneProcessEntity denseMediumCycloneProcessEntity = new DenseMediumCycloneProcessEntity();
        denseMediumCycloneProcessEntity.setProcessId(processId);
        denseMediumCycloneProcessEntity.setId(getRandomId());
        denseMediumCycloneProcessEntity.setMaterialInput(input);
        // 精煤算法
        BigDecimal bdInput = BigDecimal.valueOf(input);
        BigDecimal bdCleanCoal = bdInput.multiply(BigDecimal.valueOf(0.93));
        double cleanCoal = bdCleanCoal.doubleValue();

        // 煤矸混合物
        double coalGangueMixture = bdInput.subtract(bdCleanCoal).doubleValue();

        denseMediumCycloneProcessEntity.setCleanCoal(cleanCoal);
        denseMediumCycloneProcessEntity.setCoalGangueMixture(coalGangueMixture);

        denseMediumCycloneDao.addProcess(denseMediumCycloneProcessEntity);

        return denseMediumCycloneProcessEntity;

    }

    /**
     * 脱介筛
     * @param input
     * @param processId
     * @return
     */
    private DetachmentScreenProcessEntity detachmentScreenProcess(Double input, String processId) {
        DetachmentScreenProcessEntity detachmentScreenProcessEntity = new DetachmentScreenProcessEntity();
        detachmentScreenProcessEntity.setProcessId(processId);
        detachmentScreenProcessEntity.setId(getRandomId());
        detachmentScreenProcessEntity.setMaterialInput(input);

        // 精煤算法
        BigDecimal bdInput = BigDecimal.valueOf(input);
        BigDecimal bdCleanCoal = bdInput.multiply(BigDecimal.valueOf(0.9));
        double cleanCoal = bdCleanCoal.doubleValue();

        // 介质算法
        double media = bdInput.subtract(bdCleanCoal).doubleValue();

        detachmentScreenProcessEntity.setCleanCoalOutput(cleanCoal);
        detachmentScreenProcessEntity.setMediaOutput(media);

        detachmentScreenDao.addProcess(detachmentScreenProcessEntity);

        return detachmentScreenProcessEntity;

    }

    /**
     * 旋流器
     * @param input
     * @param processId
     * @return
     */
    private CycloneProcessEntity cycloneProcess(Double input, String processId) {
        CycloneProcessEntity cycloneProcessEntity = new CycloneProcessEntity();
        cycloneProcessEntity.setId(getRandomId());
        cycloneProcessEntity.setProcessId(processId);
        cycloneProcessEntity.setMaterialInput(input);
        // 计算中煤产量
        BigDecimal bdInput = BigDecimal.valueOf(input);
        BigDecimal bdMediumCoal = bdInput.multiply(BigDecimal.valueOf(0.92));
        double mediumCoal = bdMediumCoal.doubleValue();

        // 计算矸石量
        double gangue = bdInput.subtract(bdMediumCoal).doubleValue();

        cycloneProcessEntity.setMediumCoal(mediumCoal);
        cycloneProcessEntity.setGangue(gangue);

        cycloneProcessDao.addProcess(cycloneProcessEntity);

        return cycloneProcessEntity;

    }

    /**
     * 获取uuid
     * @return
     */
    private String getRandomId() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }
}
